package com.shine.filter;

import com.alibaba.fastjson2.JSON;
import com.shine.constant.GatewayConstant;
import com.shine.rabbitmq.request.CommonLogRequest;
import com.shine.rabbitmq.constant.RabbitConstant;
import com.shine.rabbitmq.sender.MessageSender;
import com.shine.security.authorization.Principal;
import com.shine.security.authorization.impl.AuthorityPrincipal;
import com.shine.security.context.SecurityContextHolder;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @author huihui
 * @date 2024/11/4 11:24
 * @description RequestLogFilter 请求日志
 */
@Slf4j
@Component
public class RequestLogFilter extends CommonGlobalFilter implements GlobalFilter, Ordered {

    @Resource
    private MessageSender messageSender;

    @Override
    public int getOrder() {
        return GatewayConstant.FILTER_ORDER_REQUEST_LOG;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String uri = request.getURI().toString();
        String path = request.getPath().value();
        log.info("请求uri：{}", uri);
//        log.info("请求path：{}", path);
        // 1. 从 X-Forwarded-For 获取原始客户端 IP
        String ip = request.getHeaders().getFirst("X-Forwarded-For");
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0].trim(); // 取第一个
        }
        Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
        String serviceName = null;
        if (route != null) {
            serviceName = route.getUri().getHost();  // 比如 "log-service"
        }
        // 2. 如果 header 中没有，退回使用 remoteAddress
        if (ip == null || ip.isEmpty()) {
            ip = Optional.ofNullable(request.getRemoteAddress())
                    .map(addr -> addr.getAddress().getHostAddress())
                    .orElse(null);
        }
        String traceId = request.getHeaders().getFirst(GatewayConstant.TRACE_ID_HEADER);
        HttpMethod method = request.getMethod();
        String methodName = method.name();
        HttpHeaders headers = exchange.getRequest().getHeaders();
        Map<String, Object> headersMap = new HashMap<>();
        headers.forEach((key, values) -> headersMap.put(key, String.join(",", values)));
        MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
        Map<String, Object> paramMap = new HashMap<>();
        queryParams.forEach((key, values) -> paramMap.put(key, String.join(",", values)));
        String headersJson = JSON.toJSONString(headersMap);
        String paramsJson = JSON.toJSONString(paramMap);
        Principal user = null;
        try {
            user = SecurityContextHolder.getContext().getPrincipal();
        } catch (Exception e) {
            user = new AuthorityPrincipal();
        }
        CommonLogRequest commonLogRequest = new CommonLogRequest();
        commonLogRequest.setTraceId(traceId);
        commonLogRequest.setService(serviceName);
        commonLogRequest.setUri(uri);
        commonLogRequest.setPath(path);
        commonLogRequest.setClientId(user.getClientId());
        commonLogRequest.setUserId(user.getId());
        commonLogRequest.setRequestTime(LocalDateTime.now());
        commonLogRequest.setUsername(user.getUsername());
        commonLogRequest.setIp(ip);
        commonLogRequest.setRequestMethod(methodName);
        commonLogRequest.setRequestHeaders(headersJson);
        commonLogRequest.setRequestParams(paramsJson);
        messageSender.send(RabbitConstant.Gateway.COMMON_LOG_EXCHANGE, RabbitConstant.Gateway.COMMON_LOG_KEY, commonLogRequest);
        return chain.filter(exchange);
    }

}
